#include "parse_proto.h"
#include "special_trigger.h"

#include "dc_util.h"

using namespace DcAdr;

ParseProto::ParseProto(/* args */)
{
}

ParseProto::~ParseProto()
{
}

bool ParseProto::parseCondRuleJson(const Json::Value &value)
{
    Json::Value signalJson = value["condProtoCollect"];
    if (value.isMember("isUploadDesensFile"))
    {
        global_data::g_isUploadDesensFile = JsonToValue<bool>(value["isUploadDesensFile"]);
    }    
    if (value.isMember("debugFlag"))
    {
        global_data::g_debugFlag = JsonToValue<int>(value["debugFlag"]);
    }
    
    if (value.isMember("topicNum") && value["topicNum"].isArray())
    {
        int oneNum = 0;
        string oneStrtopic;

        for (int j = 0; j < value["topicNum"].size(); ++j)
        {
            Json::Value oneTopic = value["topicNum"][j];
            oneNum = JsonToValue<int>(oneTopic["num"]);
            oneStrtopic = JsonToValue<string>(oneTopic["topic"]);           

            global_data::g_topics_map.insert({oneNum, oneStrtopic});
        }
    }
    
    if (value.isMember("blackWhiteList"))//黑白名单
    {
        if (value["blackWhiteList"].isMember("blackTopicSet"))
        {
            Json::Value BlackTopicSet = value["blackWhiteList"]["blackTopicSet"];
            if (BlackTopicSet.isArray())
            {
                int onetopicNum;
                for (int k = 0; k < BlackTopicSet.size(); ++k)
                {
                    onetopicNum = JsonToValue<int>(BlackTopicSet[k]);                    
                    
                    auto it = global_data::g_topics_map.find(onetopicNum);
                    if ( it != global_data::g_topics_map.end())
                    {                        
                        global_data::blackTopicSet.insert(it->second);
                    }                   
                }
            }
        }

        if (value["blackWhiteList"].isMember("noLimitBigSet"))
        {
            Json::Value NoLimitBigSet = value["blackWhiteList"]["noLimitBigSet"];
            if (NoLimitBigSet.isArray())
            {
                int onetopicNum;
                for (int k = 0; k < NoLimitBigSet.size(); ++k)
                {
                    onetopicNum = JsonToValue<int>(NoLimitBigSet[k]);

                    auto it = global_data::g_topics_map.find(onetopicNum);
                    if ( it != global_data::g_topics_map.end())
                    {                        
                        global_data::noLimitBigSet.insert(it->second);
                    }                
                }
            }
        }
    }

    Log_Info("g_isUploadDesensFile:{} g_debugFlag:{} g_topics_map.size:{} blackTopicSet.size:{} noLimitBigSet.size:{}", global_data::g_isUploadDesensFile, global_data::g_debugFlag, global_data::g_topics_map.size(), global_data::blackTopicSet.size(), global_data::noLimitBigSet.size());

    // 文件分片最大值和分片大小加载
    if (value.isMember("fileChunkSize"))
    {
        // 避免极端情况，小于默认100M，不赋值
        double fileChunkSize = JsonToValue<double>(value["fileChunkSize"]);
        if (fileChunkSize >= global_data::g_file_chunk_size)
        {
            global_data::g_file_chunk_size = JsonToValue<double>(value["fileChunkSize"]);
        }
    }
    if (value.isMember("perChunkSize"))
    {
        // 避免极端情况，小于默认20M，不赋值
        double perChunkSize = JsonToValue<double>(value["perChunkSize"]);
        if (perChunkSize >= global_data::g_per_chunk_size)
        {
            global_data::g_per_chunk_size = JsonToValue<double>(value["perChunkSize"]);
        }
    }
    Log_Info("g_file_chunk_size:{} g_per_chunk_size:{}", global_data::g_file_chunk_size, global_data::g_per_chunk_size);
    
    if (!signalJson.isArray())
    {
        Log_Info("condProtoCollect is not array! {}", signalJson.toStyledString());
        return false;
    }
    for (int j = 0; j < signalJson.size(); ++j)
    {
        //解析单个事件规则，获取相关信息
        std::shared_ptr<ProtoCondInfo_t> protoRuleInfo = std::make_shared<ProtoCondInfo_t>();
        auto condiInfo = signalJson[j];
        protoRuleInfo->serviceKey = JsonToValue<std::string>(condiInfo["sk"]);
        protoRuleInfo->method = JsonToValue<std::string>(condiInfo["m"]);
        protoRuleInfo->eventName = JsonToValue<std::string>(condiInfo["eventName"]);
        protoRuleInfo->level = JsonToValue<int>(condiInfo["level"]);

        
        protoRuleInfo->beforeTime = JsonToValue<double>(condiInfo["beforeTime"]);
        protoRuleInfo->laterTime = JsonToValue<double>(condiInfo["laterTime"]);
        if (condiInfo.isMember("limitTime"))
        {
            protoRuleInfo->limitTime = JsonToValue<double>(condiInfo["limitTime"]);
        }

        if (condiInfo.isMember("specialRelatedTopic") && condiInfo["specialRelatedTopic"].isArray())
        {
            for (uint32_t jj = 0; jj < condiInfo["specialRelatedTopic"].size(); jj++)
            {
                string speTopic = JsonToValue<std::string>(condiInfo["specialRelatedTopic"][jj]);
                protoRuleInfo->specialRelatedTopic.push_back(speTopic);

                //条件判断的白名单，这个proto触发条件判断,去重EventID
                std::vector<std::string> eventIDVector = m_topicEventIDList[speTopic];
                if (!Contain_List(eventIDVector, protoRuleInfo->eventName))
                {
                    Log_Info("Proto condition rule white list;event:{} related_topic:{} ", protoRuleInfo->eventName, speTopic);
                    m_topicEventIDList[speTopic].push_back(protoRuleInfo->eventName);
                    SpecialTrigger::getInstance().push2TopicMap(speTopic, protoRuleInfo->eventName);
                }
            }
        }
        else //非特殊事件有规则
        {
            //解析规则，开始
            Json::Value ruleDetails = condiInfo["ruleDetails"];
            protoRuleInfo->rules = parseRuleInfo(ruleDetails, protoRuleInfo->eventName);
            Json::Value ruleDetailsEnd = condiInfo["ruleDetailsEnd"];
            if (!ruleDetailsEnd.empty()) //判断为json array
            {
                protoRuleInfo->rulesEnd = parseRuleInfo(ruleDetailsEnd, protoRuleInfo->eventName);
            }
        }

        //获取事件要采集的数据
        if (condiInfo.isMember("collectTopics"))
        {
            Json::Value collectData = condiInfo["collectTopics"];
            parseCollectData(collectData, protoRuleInfo->collectData);
        }    
        // if (condiInfo.isMember("collectData")) //r14的代码就不再兼容这种采集配置方式
        // {
        //     Json::Value collectData = condiInfo["collectData"];
        //     protoRuleInfo->collectData = parseCollectData(collectData);
        // }    

        //存入列表
        m_protoRuleList[protoRuleInfo->eventName] = protoRuleInfo;
        Log_Info("Event rule add eventName:{} ", protoRuleInfo->eventName);
    }
    return true;
}

bool ParseProto::parseSignalCollect(const Json::Value &value)
{
    Log_Signal("Parse signal collect");
    Json::Value signalJson = value["signalCollect"];
    if (!signalJson.isArray())
    {
        Log_Signal("signalCollect is not array! {}", signalJson.toStyledString());
        return false;
    }
    for (int i = 0; i < signalJson.size(); ++i)
    {
        ProtoCondRuleSignalInfo_t signalRuleInfo;
        std::string names = JsonToValue<std::string>(signalJson[i]["name"]);
        signalRuleInfo.topic = JsonToValue<std::string>(signalJson[i]["topic"]);
        signalRuleInfo.protoMsg = JsonToValue<std::string>(signalJson[i]["protoMsg"]);
        signalRuleInfo.signalName = JsonToValue<std::string>(signalJson[i]["signalName"]);
        signalRuleInfo.name = Util::split(names, ".");
        signalRuleInfo.opera = CRCT_NONE;

        //判断package.message格式是否准确
        if (signalRuleInfo.topic.find(signalRuleInfo.protoMsg) == std::string::npos)
        {
            Log_Signal("ERROR: topic not contains protoMsg, signal name: {}  topic: {}  protoMsg: {}  names: {}", signalRuleInfo.signalName, signalRuleInfo.topic, signalRuleInfo.protoMsg, names);
            continue;
        }

        //校验，能否缓存对应的topic和解析器
        ::google::protobuf::Message *msg = nullptr;
        if (dynamicParseFromPBFile(signalRuleInfo.protoMsg, msg) == 0)
        {
            //存入队列
            m_protoMessage[signalRuleInfo.topic] = msg;
            m_protoSignalParser[signalRuleInfo.topic].push_back(signalRuleInfo);
            // Log_Signal("signalCollect add signal, signal name: {}  topic: {}  protoMsg: {} names: {}"
            //             , signalRuleInfo.signalName
            //             , signalRuleInfo.topic
            //             , signalRuleInfo.protoMsg
            //             , Util::queueToString(signalRuleInfo.name));
        }
        else
        {
            Log_Signal("ERROR: signalCollect add signal, signal name: {}  topic: {}  protoMsg: {} names: {}", signalRuleInfo.signalName, signalRuleInfo.topic, signalRuleInfo.protoMsg, names);
        }
    }
    return true;
}

bool ParseProto::parseTriggerConfigJsonData(const std::string &json)
{
    Log_Info("parseTriggerConfigJsonData start ......");
    Json::Reader reader;
    Json::Value root, data, signalJson, collectData;
    if (!reader.parse(json, root))
    {
        Log_Info("json parse error! {}", json);
        return false;
    }
    data = root["data"];
    parseCondRuleJson(data);
    return true;
}

bool ParseProto::parseSignalConfigJsonData(const std::string &json)
{
    Log_Info("parseSignalConfigJsonData start ......");
    Json::Reader reader;
    Json::Value root, data, signalJson, collectData;
    if (!reader.parse(json, root))
    {
        Log_Info("json parse error! {}", json);
        return false;
    }
    data = root["data"];
    parseSignalCollect(data);
    Log_Info("parseSignalConfigJsonData end ......");
    return true;
}

void ParseProto::addElementsToVec(const std::vector<std::string> &srcVec, std::vector<std::string> &desVec)
{
    for (auto it = srcVec.begin(); it != srcVec.end(); it++)
    {
        desVec.push_back(*it);
    }
}

void ParseProto::parseCollectData(const Json::Value &jsons, vector<std::string>& outVec)
{
    if (!jsons.isArray())
    {
        Log_Info("error collectTopics not is array");
        return;
    }
    for (int j = 0; j < jsons.size(); j++)
    {
        int data = JsonToValue<int>(jsons[j]);

        if (Contain_Map(global_data::g_topics_map, data))
        {
            outVec.push_back(global_data::g_topics_map[data]);//配置里的编号映射成采集哪个topic
        }

    }

    Log_Info("pare event need collectVec.size(): {}", outVec.size());

    return;
}

std::vector<std::string> ParseProto::parseCollectData(const Json::Value &jsons)
{
    std::vector<std::string> collectVec;

    if (!jsons.isArray())
    {
        Log_Info("error collectData not is array");
        return collectVec;
    }
    for (int j = 0; j < jsons.size(); j++)
    {
        int data = JsonToValue<int>(jsons[j]);
        if (data == 1)
        {
            addElementsToVec(global_data::g_topics_mid, collectVec);
        }
        else if (data == 2)
        {
            addElementsToVec(global_data::g_topics_vedio, collectVec);
        }
        else if (data == 3)
        {
            addElementsToVec(global_data::g_topics_pic, collectVec);
        }
    }

    Log_Info("pare event need collectVec.size(): {}", collectVec.size());

    return collectVec;
}

std::shared_ptr<ProtoCondRule_t> ParseProto::parseRuleInfo(const Json::Value &jsons, const std::string &eventID)
{
    auto singalJson = jsons["expressRule"];
    if (!singalJson.isArray()) //判断为json array
    {
        Log_Info("expressRule is not array! {}", jsons.toStyledString());
        return nullptr;
    }
    std::shared_ptr<ProtoCondRule_t> condRule = std::make_shared<ProtoCondRule_t>();
    condRule->expressRuleType = (CondRuleType)JsonToValue<int>(jsons["expressRuleType"]);
    condRule->triggerTimesExpect = JsonToValue<int>(jsons["triggerTimes"]);
    condRule->childRuleType = (CondRuleType)JsonToValue<int>(jsons["childRuleType"]);
    for (uint32_t i = 0; i < singalJson.size(); i++)
    {
        //解析单个信号规则
        ProtoCondRuleSignalInfo_t signalRuleInfo;
        std::string names = JsonToValue<std::string>(singalJson[i]["name"]);
        signalRuleInfo.opera = (CondRuleCompareType)JsonToValue<int>(singalJson[i]["opera"]);
        signalRuleInfo.valueType = JsonToValue<std::string>(singalJson[i]["valueType"]);
        signalRuleInfo.constValue = (singalJson[i]["constValue"]);

        if (singalJson[i].isMember("change") && singalJson[i]["change"].isArray())
        {
            for (uint32_t jj = 0; jj < singalJson[i]["change"].size(); jj++)
            {
                signalRuleInfo.changeVec.push_back(JsonToValue<double>(singalJson[i]["change"][jj]));
            }
        }

        // 持续时间
        if (singalJson[i].isMember("time"))
        {
            signalRuleInfo.time = JsonToValue<uint64_t>(singalJson[i]["time"]);
        }

        signalRuleInfo.topic = JsonToValue<std::string>(singalJson[i]["topic"]);
        signalRuleInfo.protoMsg = JsonToValue<std::string>(singalJson[i]["protoMsg"]);
        signalRuleInfo.id = JsonToValue<std::string>(singalJson[i]["id"]);
        signalRuleInfo.name = Util::split(names, ".");
        Log_Info("signalRuleInfo name: {}  opera: {}  constValue: {}  topic: {}  protoMsg: {}  id: {}", names, signalRuleInfo.opera, signalRuleInfo.constValue.toStyledString(), signalRuleInfo.topic, signalRuleInfo.protoMsg, signalRuleInfo.id);
        condRule->expressRule.push_back(signalRuleInfo);

        //缓存对应的topic和解析器
        ::google::protobuf::Message *msg = nullptr;
        if (dynamicParseFromPBFile(signalRuleInfo.protoMsg, msg) == 0)
        {
            m_protoMessage[signalRuleInfo.topic] = msg;
            Log_Info("Proto init success topic: {} ", signalRuleInfo.topic);
        }

        //条件判断的白名单，这个proto触发条件判断,去重EventID
        std::vector<std::string>
            eventIDVector = m_topicEventIDList[signalRuleInfo.topic];
        if (!Contain_List(eventIDVector, eventID))
        {
            Log_Info("Proto condition rule white list;event:{} related_topic:{} ", eventID, signalRuleInfo.topic);
            m_topicEventIDList[signalRuleInfo.topic].push_back(eventID);
        }
    }
    //获取是否有子规则
    auto childRuleJson = jsons["childRule"];
    if (childRuleJson.isNull() || !childRuleJson.isObject() || condRule->expressRule.empty())
    {
        condRule->childRule = nullptr;
    }
    else
    {
        condRule->childRule = parseRuleInfo(childRuleJson, eventID);
    }
    return condRule;
}

void ParseProto::initProto()
{
    // 1.初始化proto文件,加载所有proto文件
    std::string path = global_data::g_proto_path;
    std::vector<std::string> fileNameList = Util::getFilesByDir(path);

    // TODO 检查文件名是否合法
    DiskSourceTree sourceTree;
    sourceTree.MapPath("", path);
    m_importer = new Importer(&sourceTree, NULL);
    Log_Info("gd init proto files size: {}", fileNameList.size());
    for (auto &fileName : fileNameList)
    {
        const FileDescriptor *fileDes = m_importer->Import(fileName);
        if (!fileDes)
        {
            Log_Info("Proto Importer , fileName: {}  result: {}", fileName, (fileDes != nullptr));
        }
    }
    Log_Info("gd init proto sucess: ");
    m_factory = new DynamicMessageFactory();

    // 2.初始化配置文件
}

int ParseProto::dynamicParseFromPBFile(const std::string &classname, ::google::protobuf::Message *&msg)
{
    auto *descriptor = m_importer->pool()->FindMessageTypeByName(classname);
    if (!descriptor)
    {
        Log_ERROR("descriptor find null {}", classname);
        return 1;
    }

    const ::google::protobuf::Message *message = m_factory->GetPrototype(descriptor);
    if (!message)
    {
        Log_ERROR("msg find null {}", classname);
        return 2;
    }
    msg = message->New();
    if (!msg)
    {
        Log_ERROR("msg create null {}", classname);
        return 3;
    }
    return 0;
}

google::protobuf::Message *ParseProto::getProtoMessageByTopic(std::string &topic)
{
    return m_protoMessage[topic];
}

bool ParseProto::protoRuleContainTopic(const std::string &topic)
{
    return Contain_Map(m_topicEventIDList, topic);
}